package PrincipleOfCompiler.Ex2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TinyPlusLexer {
    private String sourceCode;
    private int currentIndex;
    private int lineNumber;

    // 关键字集合
    private static final List<String> keywords = Arrays.asList(
            "true", "false", "or", "and", "not", "int", "bool", "string", "float",
            "double", "do", "while", "include", "break", "continue",
            "if", "then", "else", "end", "repeat", "until", "read", "write"
    );

    private static final List<String> specialSymbols = Arrays.asList(
           ">", "<=", ">=", ",", "'", "%", "**", "{", "}", ";", ":=", "+", "-", "*", "/", "("
            , ")", "<", "="
    );

    public TinyPlusLexer(String sourceCode) {
        this.sourceCode = sourceCode;
        this.currentIndex = 0;
        this.lineNumber = 1;
    }

    public List<Token> tokenize() {
        List<Token> tokens = new ArrayList<>();

        while (currentIndex < sourceCode.length()) {
            char currentChar = sourceCode.charAt(currentIndex);

            // 跳过空白字符
            if (Character.isWhitespace(currentChar)) {
                if (currentChar == '\n') {
                    lineNumber++;
                }
                currentIndex++;
                continue;
            }

            // 处理关键字、符号、标识符、数字和字符串
            if (Character.isLetter(currentChar)) {
                String word = readWord();
                if (keywords.contains(word)) {
                    tokens.add(new Token(TokenType.KEY, word));
                } else {
                    tokens.add(new Token(TokenType.ID, word));
                }
            } else if (Character.isDigit(currentChar)) {
                String number = readNumber();
                tokens.add(new Token(TokenType.NUM, number));
            } else if (currentChar == '\'') {
                String str = readString();
                if (str != null){
                    tokens.add(new Token(TokenType.STR, str));
                }
            } else if (currentChar == '{') {
                String str = readComment();
                if (str != null){
//                    tokens.add(new Token(TokenType.SYM, str));
                }
            } else {
                String symbol = readSymbol();
                if (symbol != null) {
                    tokens.add(new Token(TokenType.SYM, symbol));
                } else {
                    // 如果以上规则都不匹配，则报告词法错误
                    System.err.println("error at line " + lineNumber + ": error character \'" + currentChar + "\'");
                }
            }
        }

        return tokens;
    }

    // 读取关键字或标识符
    private String readWord() {
        StringBuilder sb = new StringBuilder();
        while (currentIndex < sourceCode.length() && (Character.isLetterOrDigit(sourceCode.charAt(currentIndex)))) {
            sb.append(sourceCode.charAt(currentIndex++));
        }
        return sb.toString();
    }

    // 读取数字
    private String readNumber() {
        StringBuilder sb = new StringBuilder();
        while (currentIndex < sourceCode.length() && (Character.isDigit(sourceCode.charAt(currentIndex)))) {
            sb.append(sourceCode.charAt(currentIndex++));
        }
        return sb.toString();
    }

    // 读取字符串
    private String readString() {
        StringBuilder sb = new StringBuilder();
        currentIndex++; // 跳过左引号
        while (currentIndex < sourceCode.length() && sourceCode.charAt(currentIndex) != '\'') {
            sb.append(sourceCode.charAt(currentIndex++));
            if (sourceCode.charAt(currentIndex) == '\n'){
                System.err.println("error at line " + lineNumber + ": unclosed string");
                return null;
            }
        }
        if (currentIndex >= sourceCode.length()) {
            System.err.println("error at line " + lineNumber + ": unclosed string");
        } else {
            currentIndex++; // 跳过右引号
            System.out.println("--------------------a correct string at line " + lineNumber);
        }
        return sb.toString();
    }

    // 读取符号
    private String readSymbol() {
        char currentChar = sourceCode.charAt(currentIndex);
        if (currentChar == ':') {
            if (currentIndex + 1 < sourceCode.length() && sourceCode.charAt(currentIndex + 1) == '=') {
                currentIndex += 2;
                return ":=";
            }
        } else if (currentChar == '{') {
            return readComment();
        } else if (currentChar == '>' || currentChar == '<') {
            if (currentIndex + 1 < sourceCode.length() && (sourceCode.charAt(currentIndex + 1) == '=')) {
                currentIndex += 2;
                return String.valueOf(currentChar) + "=";
            }else {
                currentIndex++;
                return String.valueOf(currentChar);
            }
        } else if (specialSymbols.contains("" + currentChar)){
            currentIndex++;
            return String.valueOf(currentChar);
        }
        currentIndex++;
        return null;
    }


    // 读取注释
    private String readComment() {
        StringBuilder sb = new StringBuilder();
        currentIndex++; // 跳过左大括号
        while (currentIndex < sourceCode.length() && sourceCode.charAt(currentIndex) != '}') {
            sb.append(sourceCode.charAt(currentIndex++));
        }
        if (currentIndex >= sourceCode.length()) {
            System.err.println("error at line " + lineNumber + ": unclosed comment");
        } else {
            currentIndex++; // 跳过右大括号
            System.out.println("--------------------a correct comment start from line " + lineNumber);
        }
        return sb.toString();
    }

    // 定义 Token 类
    private class Token {
        private TokenType type;
        private String value;

        public Token(TokenType type, String value) {
            this.type = type;
            this.value = value;
        }

        public TokenType getType() {
            return type;
        }

        public String getValue() {
            return value;
        }

        @Override
        public String toString() {
            return "(" + type + ", " + value + ")";
        }
    }

    // 定义 TokenType 枚举
    private enum TokenType {
        KEY, SYM, ID, NUM, STR
    }

    public static void main(String[] args) {
        String sourceCode =
                "true\tfalse\tor\tand \tnot\tint\tbool\tstring\tfloat\tuntil\tread\twrite\n" +
                        "double\tdo \twhile\tinclude\tbreak\tcontinue\tif\tthen\telse\tend\trepeat\n" +
                        ">\t<=\t>=\t,\t %\t**\t*\t/\t(\n" +
                        "{\t}\t;\t:=\t+\t-\t)\t<\t=\n" +
                        "123abc123\n" +
                        "'123 123 abc 123 编译原理'\n" +
                        "abc123abc\n" +
                        "int123\n" +
                        "intbooltrue\n" +
                        "int bool true\n" +
                        "str:= ' any character except ' ';\n" +
                        "str:= 'abcd \tefg  hijk lmn,%^$#编译原理;'\n" +
                        "str:= 'sdlgk\n" +
                        "\tint\tbool\t$\t一\n" +
                        "\tsldk'\n" +
                        "{编译原理}}\n" +
                        "{comment\n" +
                        "can\n" +
                        "include more than \n" +
                        "one line\n" +
                        "}\n" +
                        "编译原理\n" +
                        "￥\t$\t#\t^\t!\t?\t<>\t\"\n" +
                        "~\t|\t[\t]\t_\t&\t@\t.\n" +
                        "{\n" +
                        "￥\t$\t#\t^\t!\t?\t<>\t\"\n" +
                        "~\t|\t[\t]\t_\t&\t@\t.\n";
        TinyPlusLexer lexer = new TinyPlusLexer(sourceCode);
        List<Token> tokens = lexer.tokenize();
        for (Token token : tokens) {
            System.out.println(token);
        }
    }
}

